﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace G_Code_Postprocessor
{
    /// <summary> Перечисление типов перехода </summary>
    public enum TransitionType
    {
        /// <summary> Неопределён </summary>
        Undefined = 0,
        /// <summary> Установить заготовку </summary>
        Install = 1,
        /// <summary> Точить цилиндр </summary>
        ShoulderTurning = 2,
        /// <summary> Снять заготовку </summary>
        Uninstall = 3,
        /// <summary> Торцевание </summary>
        Facing = 4,
        /// <summary> Точить конус </summary>
        TaperTurning = 5,
        /// <summary> Точить радиус по часовой стрелке </summary>
        RadiusTurningClockwise = 6,
        /// <summary> Точить радиус против часовой стрелки </summary>
        RadiusTurningAnticlockwise = 7
    }
    public class Install
    {
        /// <summary> Диаметр заготовки </summary>
        public float D;
        /// <summary> Длинна заготовки </summary>
        public float L;
        /// <summary> Номер инструмента </summary>
        public int ToolNumber;
        /// <summary> Номер вылета инструмента </summary>
        public int ToolDepartureNumber;
        /// <summary> Остановить станок для смены инстумента </summary>
        public bool MachinePause;
        /// <summary> Позиция резца вдоль оси X </summary>
        public float X;
        /// <summary> Позиция резца вдоль оси Z </summary>
        public float Z;
        /// <summary> Остановить шпиндель </summary>
        public bool Stop;
        /// <summary> Завершить программу </summary>
        public bool End;

    }
    public class Uninstall
    {
        /// <summary> Диаметр заготовки </summary>
        public float D;
        /// <summary> Длинна заготовки </summary>
        public float L;
        /// <summary> Позиция резца вдоль оси X </summary>
        public float X;
        /// <summary> Позиция резца вдоль оси Z </summary>
        public float Z;
        /// <summary> Остановить шпиндель </summary>
        public bool Stop;
        /// <summary> Завершить программу </summary>
        public bool End;
    }
    public class ShoulderTurning
    {
        /// <summary> Получаемый диаметр </summary>
        public float D;
        /// <summary> Длина проточки </summary>
        public float L;
        /// <summary> Отступ от торца </summary>
        public float B;
        /// <summary> Диаметр заготовки </summary>
        public float Dpiece;
        /// <summary> Глубина резания </summary>
        public float h;
        /// <summary> Значение возврата </summary>
        public float R;
        /// <summary> Припуск на чистовую обработку </summary>
        public float U;
        /// <summary> Скорость подачи </summary>
        public float F;
        /// <summary> Скорость вращения шпинделя </summary>
        public float S;
        /// <summary> Номер инструмента </summary>
        public int ToolNumber;
        /// <summary> Номер вылета инструмента </summary>
        public int ToolDepartureNumber;
        /// <summary> Остановить станок для смены инстумента </summary>
        public bool MachinePause;
        /// <summary> Высота инструмента над зоготовкой </summary>
        public float X;
        /// <summary> Величина подвода к заготовке </summary>
        public float Z;
    }
    public class Facing
    {
        /// <summary> Получаемый диаметр заготовки </summary>
        public float D;
        /// <summary> Получаемая длинна заготовки </summary>
        public float L;
        /// <summary> Отступ от торца </summary>
        public float B;
        /// <summary> Диаметр заготовки </summary>
        public float Dpiece;
        /// <summary> Длинна заготовки </summary>
        public float Lpiece;
        /// <summary> Глубина резания </summary>
        public float h;
        /// <summary> Значение возврата </summary>
        public float R;
        /// <summary> Припуск на чистовую обработку по X </summary>
        public float U;
        /// <summary> Припуск на чистовую обработку по Z </summary>
        public float W;
        /// <summary> Скорость подачи </summary>
        public float F;
        /// <summary> Скорость вращения шпинделя </summary>
        public float S;
        /// <summary> Номер инструмента </summary>
        public int ToolNumber;
        /// <summary> Номер вылета инструмента </summary>
        public int ToolDepartureNumber;
        /// <summary> Остановить станок для смены инстумента </summary>
        public bool MachinePause;
        /// <summary> Высота инструмента над зоготовкой </summary>
        public float X;
        /// <summary> Величина подвода к заготовке </summary>
        public float Z;
    }
    public class TaperTurning
    {
        /// <summary> Больший диаметр </summary>
        public float D;
        /// <summary> Получаемая длинна заготовки </summary>
        public float L;
        /// <summary> Отступ от торца </summary>
        public float B;
        /// <summary> Диаметр заготовки </summary>
        public float Dpiece;
        /// <summary> Длинна заготовки </summary>
        public float Lpiece;
        /// <summary> Глубина резания </summary>
        public float h;
        /// <summary> Значение возврата </summary>
        public float R;
        /// <summary> Припуск на чистовую обработку по X </summary>
        public float U;
        /// <summary> Припуск на чистовую обработку по Z </summary>
        public float W;
        /// <summary> Скорость подачи </summary>
        public float F;
        /// <summary> Скорость вращения шпинделя </summary>
        public float S;
        /// <summary> Номер инструмента </summary>
        public int ToolNumber;
        /// <summary> Номер вылета инструмента </summary>
        public int ToolDepartureNumber;
        /// <summary> Остановить станок для смены инстумента </summary>
        public bool MachinePause;
        /// <summary> Высота инструмента над зоготовкой </summary>
        public float X;
        /// <summary> Величина подвода к заготовке </summary>
        public float Z;
        /// <summary> Меньший диаметр </summary>
        public float d;
        /// <summary> Тангенс угла уклона </summary>
        public float tanalpha;
        /// <summary> Выразить через начальный диаметр и угол </summary>
        public bool anglemethod;
    }
    public class RadiusTurningClockwise
    {
        /// <summary> Больший диаметр </summary>
        public float D;
        /// <summary> Получаемая длинна заготовки </summary>
        public float L;
        /// <summary> Отступ от торца </summary>
        public float B;
        /// <summary> Диаметр заготовки </summary>
        public float Dpiece;
        /// <summary> Длинна заготовки </summary>
        public float Lpiece;
        /// <summary> Глубина резания </summary>
        public float h;
        /// <summary> Значение возврата </summary>
        public float R;
        /// <summary> Припуск на чистовую обработку по X </summary>
        public float U;
        /// <summary> Припуск на чистовую обработку по Z </summary>
        public float W;
        /// <summary> Скорость подачи </summary>
        public float F;
        /// <summary> Скорость вращения шпинделя </summary>
        public float S;
        /// <summary> Номер инструмента </summary>
        public int ToolNumber;
        /// <summary> Номер вылета инструмента </summary>
        public int ToolDepartureNumber;
        /// <summary> Остановить станок для смены инстумента </summary>
        public bool MachinePause;
        /// <summary> Высота инструмента над зоготовкой </summary>
        public float X;
        /// <summary> Величина подвода к заготовке </summary>
        public float Z;
        /// <summary> Меньший диаметр </summary>
        public float d;
        /// <summary> Радиус </summary>
        public float r;
    }
    public class RadiusTurningAnticlockwise
    {
        /// <summary> Больший диаметр </summary>
        public float D;
        /// <summary> Получаемая длинна заготовки </summary>
        public float L;
        /// <summary> Отступ от торца </summary>
        public float B;
        /// <summary> Диаметр заготовки </summary>
        public float Dpiece;
        /// <summary> Длинна заготовки </summary>
        public float Lpiece;
        /// <summary> Глубина резания </summary>
        public float h;
        /// <summary> Значение возврата </summary>
        public float R;
        /// <summary> Припуск на чистовую обработку по X </summary>
        public float U;
        /// <summary> Припуск на чистовую обработку по Z </summary>
        public float W;
        /// <summary> Скорость подачи </summary>
        public float F;
        /// <summary> Скорость вращения шпинделя </summary>
        public float S;
        /// <summary> Номер инструмента </summary>
        public int ToolNumber;
        /// <summary> Номер вылета инструмента </summary>
        public int ToolDepartureNumber;
        /// <summary> Остановить станок для смены инстумента </summary>
        public bool MachinePause;
        /// <summary> Высота инструмента над зоготовкой </summary>
        public float X;
        /// <summary> Величина подвода к заготовке </summary>
        public float Z;
        /// <summary> Меньший диаметр </summary>
        public float d;
        /// <summary> Радиус </summary>
        public float r;
    }

    /// <summary> Класс технологического перехода </summary>
    public class Transition
    {
        /// <summary> Тип перехода </summary>
        public TransitionType transitionType = 0;
        /// <summary> Описание перехода </summary>
        public string description = "Неописанный переход";
        /// <summary> G-код перехода </summary>
        public Gcode gcode = new Gcode();

        public ShoulderTurning shoulderTurning;
        public Install install;
        public Uninstall uninstall;
        public Facing facing;
        public TaperTurning taperTurning;
        public RadiusTurningClockwise radiusTurningClockwise;
        public RadiusTurningAnticlockwise radiusTurningAnticlockwise;


        /// <summary> Инициализация перехода </summary>
        public void Init(TransitionType transitionType)
        {
            this.gcode = new Gcode();
            this.transitionType = transitionType;
            switch (transitionType)
            {
                case TransitionType.Install:
                    install = new Install();
                    description = "Установить заготовку";
                    break;
                case TransitionType.Uninstall:
                    uninstall = new Uninstall();
                    description = "Снять заготовку";
                    break;
                case TransitionType.ShoulderTurning:
                    shoulderTurning = new ShoulderTurning();
                    description = "Точить цилиндр";
                    break;
                case TransitionType.Facing:
                    facing = new Facing();
                    description = "Торцевать";
                    break;
                case TransitionType.TaperTurning:
                    taperTurning = new TaperTurning();
                    description = "Точить конус";
                    break;
                case TransitionType.RadiusTurningClockwise:
                    radiusTurningClockwise = new RadiusTurningClockwise();
                    description = "Точить радиус по часовой стрелке";
                    break;
                case TransitionType.RadiusTurningAnticlockwise:
                    radiusTurningAnticlockwise = new RadiusTurningAnticlockwise();
                    description = "Точить радиус против часовой стрелки";
                    break;
                default:
                    break;
            }
        }

        public bool GenerateGcode(int framesCount, bool frameNumbers)
        {
            gcode = new Gcode();
            gcode.framesOffset = framesCount;
            gcode.frameNumbers = frameNumbers;

            switch (transitionType)
            {
                case TransitionType.Install:
                    {
                        
                        float D = install.D;
                        float L = install.L;
                        int ToolNumber = install.ToolNumber;
                        int ToolDepartureNumber = install.ToolDepartureNumber;
                        bool MachinePause = install.MachinePause;
                        float X = install.X;
                        float Z = install.Z;
                        bool Stop = install.Stop;
                        bool End = install.End;
                        
                        gcode.AddFrame(gcode.SetTheTool(ToolNumber, ToolDepartureNumber));
                        gcode.AddFrame(gcode.SetThePlaneXZ()
                             + gcode.SetMetricCoords()
                             + gcode.SetAbsoluteCoords()
                             + gcode.SetCoordSystem(Gcode.Offset.Offset1)); //ноль на торце заготовки
                        if (Stop) gcode.AddFrame(gcode.StopTheRotation());
                        gcode.AddFrame(gcode.FastMove(2 * X, Z) + "\n\n");//ноль на торце заготовки
                        if (End) gcode.frames.Add("M02");
                        if (MachinePause) gcode.AddFrame(gcode.StopWithContinuationIfNecessary());
                        return true;
                    }
                case TransitionType.Uninstall:
                    {
                        float D = uninstall.D;
                        float L = uninstall.L;
                        float X = uninstall.X;
                        float Z = uninstall.Z;
                        bool Stop = uninstall.Stop;
                        bool End = uninstall.End;

                        if (Stop) gcode.AddFrame(gcode.StopTheRotation());
                        gcode.AddFrame(gcode.FastMove(2 * X, Z));//ноль на торце заготовки
                        if (End) gcode.frames.Add("M02");
                        return true;
                    }
                case TransitionType.ShoulderTurning:
                    {
                        float D = shoulderTurning.D;
                        float L = shoulderTurning.L;
                        float Dpiece = shoulderTurning.Dpiece;
                        float U = shoulderTurning.U;
                        float F = shoulderTurning.F;
                        float h = shoulderTurning.h;
                        float R = shoulderTurning.R;
                        float S = shoulderTurning.S;
                        float X = shoulderTurning.X;
                        float Z = shoulderTurning.Z;
                        float B = shoulderTurning.B;
                        int ToolNumber = shoulderTurning.ToolNumber;
                        int ToolDepartureNumber = shoulderTurning.ToolDepartureNumber;
                        bool MachinePause = shoulderTurning.MachinePause;

                        //Dpiece = D + 2*U + 2*ost + 2*n*h
                        int n = (int)((Dpiece - D - 2*U) / (2*h));
                        float ost = (Dpiece - D - 2 * U) - (2 * n * h);

                        float tx = 0;
                        float tz = 0;

                        if (MachinePause) gcode.AddFrame(gcode.StopWithContinuationIfNecessary());
                        gcode.AddFrame(gcode.SetTheTool(ToolNumber, ToolDepartureNumber));
                        gcode.AddFrame(gcode.SetTheRotationClockwise(S) + "\n");
                        for (int i = 1; i <= n; i++)
                        {
                            tx = Dpiece - 2 * h * i; tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx, tz));

                            //gcode.AddFrame(gcode.SetRelativeCoords());

                            tx += 0; tz += -(L + Z);
                            gcode.AddFrame(gcode.Move(tx, tz, F));

                            tx += R; tz += 0;
                            gcode.AddFrame(gcode.Move(tx, tz, F));

                            //gcode.AddFrame(gcode.SetAbsoluteCoords());

                            tx = Dpiece - 2 * h * i; tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx + 2 * X, tz) + "\n"
                                + ((ost > 0.00001) ? "" : "\n"));
                        }
                        if (ost > 0.00001)
                        {
                            tx = D + 2 * U; tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx, tz));
                            
                            //gcode.AddFrame(gcode.SetRelativeCoords());

                            tx += 0; tz += -(L + Z);
                            gcode.AddFrame(gcode.Move(tx, tz, F));

                            tx += R; tz += 0;
                            gcode.AddFrame(gcode.Move(tx, tz, F));

                            //gcode.AddFrame(gcode.SetAbsoluteCoords());

                            tx = D + 2 * U; tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx + 2 * X, tz) + "\n\n");
                        }
                        /*
                        for (int i = 1; i <= n; i++)
                        {
                            gcode.AddFrame(gcode.FastMove(Dpiece - 2 * h * i, Z - B));
                            gcode.AddFrame(gcode.SetRelativeCoords());
                            gcode.AddFrame(gcode.Move(0, -(L + Z), F));
                            gcode.AddFrame(gcode.Move(R, 0, F));
                            gcode.AddFrame(gcode.SetAbsoluteCoords());
                            gcode.AddFrame(gcode.FastMove(Dpiece - 2 * h * i + 2 * X, Z - B) + "\n"
                                + ((ost > 0.00001) ? "" : "\n"));
                        }
                        if (ost > 0.00001)
                        {
                            gcode.AddFrame(gcode.FastMove(D + 2 * U, Z - B));
                            gcode.AddFrame(gcode.SetRelativeCoords());
                            gcode.AddFrame(gcode.Move(0, -(L + Z), F));
                            gcode.AddFrame(gcode.Move(R, 0, F));
                            gcode.AddFrame(gcode.SetAbsoluteCoords());
                            gcode.AddFrame(gcode.FastMove(D + 2 * U + 2 * X, Z - B) + "\n\n");
                        }*/
                        return true;
                    }
                case TransitionType.Facing:
                    {
                        float D = facing.D;
                        float L = facing.L;
                        float Dpiece = facing.Dpiece;
                        float Lpiece = facing.Lpiece;
                        float U = facing.U;
                        float W = facing.W;
                        float F = facing.F;
                        float h = facing.h;
                        float R = facing.R;
                        float S = facing.S;
                        float X = facing.X;
                        float Z = facing.Z;
                        float B = facing.B;
                        int ToolNumber = facing.ToolNumber;
                        int ToolDepartureNumber = facing.ToolDepartureNumber;
                        bool MachinePause = facing.MachinePause;

                        //Lpiece = L + W + ost + n*h + B
                        int n = (int)((Lpiece - L - W - B) / h);
                        float ost = Lpiece - L - W - B - (n * h);

                        float tx = 0;
                        float tz = 0;

                        //Dpiece = D + 2*U

                        if (MachinePause) gcode.AddFrame(gcode.StopWithContinuationIfNecessary());
                        gcode.AddFrame(gcode.SetTheTool(ToolNumber, ToolDepartureNumber));
                        gcode.AddFrame(gcode.SetTheRotationClockwise(S) + "\n");

                        for (int i = 1; i <= n; i++)
                        {
                            tx = Dpiece + 2 * X; tz = -B - i * h;
                            gcode.AddFrame(gcode.FastMove(tx, tz)); //подвод

                            //gcode.AddFrame(gcode.SetRelativeCoords());

                            tx += -(Dpiece + 2 * X - D - 2 * U); tz += 0;
                            gcode.AddFrame(gcode.Move(tx, tz, F)); //проход

                            tx += 0; tz += R;
                            gcode.AddFrame(gcode.Move(tx, tz, F)); //возврат

                            //gcode.AddFrame(gcode.SetAbsoluteCoords());

                            tx = Dpiece + 2 * X; tz = -B - i * h;
                            gcode.AddFrame(gcode.FastMove(tx, tz + Z) + "\n"
                                 + ((ost > 0.00001) ? "" : "\n")); //отвод
                        }
                        if (ost > 0.00001)
                        {
                            tx = Dpiece + 2 * X; tz = -B - n * h - ost;
                            gcode.AddFrame(gcode.FastMove(tx, tz)); //подвод

                            //gcode.AddFrame(gcode.SetRelativeCoords());

                            tx += -(Dpiece + 2 * X - D - 2 * U); tz += 0;
                            gcode.AddFrame(gcode.Move(tx, tz, F)); //проход

                            tx += 0; tz += R;
                            gcode.AddFrame(gcode.Move(tx, tz, F)); //возврат

                            //gcode.AddFrame(gcode.SetAbsoluteCoords());

                            tx = Dpiece + 2 * X; tz = -B - n * h;
                            gcode.AddFrame(gcode.FastMove(tx, tz + Z) + "\n\n"); //отвод
                        }
                        return true;
                    }
                case TransitionType.TaperTurning:
                    {
                        float D = taperTurning.D;
                        float L = taperTurning.L;
                        float Dpiece = taperTurning.Dpiece;
                        float Lpiece = taperTurning.Lpiece;
                        float U = taperTurning.U;
                        float W = taperTurning.W;
                        float F = taperTurning.F;
                        float h = taperTurning.h;
                        float R = taperTurning.R;
                        float S = taperTurning.S;
                        float X = taperTurning.X;
                        float Z = taperTurning.Z;
                        float B = taperTurning.B;
                        int ToolNumber = taperTurning.ToolNumber;
                        int ToolDepartureNumber = taperTurning.ToolDepartureNumber;
                        bool MachinePause = taperTurning.MachinePause;
                        float d = taperTurning.d;
                        float tanalpha = taperTurning.tanalpha;
                        bool anglemethod = taperTurning.anglemethod;

                        if (!anglemethod) tanalpha = (D - d) / (2 * L);
                        float koef = (float)Math.Sqrt(tanalpha * tanalpha + 1);
                        h *= koef; U *= koef;
                        float dxL = 2 * L * tanalpha;
                        float dxZ = 2 * Z * tanalpha;


                        //Dpiece = D + 2*U + 2*ost + 2*n*h
                        int n = (int)((Dpiece - d - 2 * U) / (2 * h));
                        float ost = (Dpiece - d - 2 * U) - (2 * n * h);

                        float tx = Dpiece;
                        float tz = Z - B;

                        if (MachinePause) gcode.AddFrame(gcode.StopWithContinuationIfNecessary());
                        gcode.AddFrame(gcode.SetTheTool(ToolNumber, ToolDepartureNumber));
                        gcode.AddFrame(gcode.SetTheRotationClockwise(S) + "\n");

                        for (int i = 1; i <= n; i++)
                        {
                            tx = Dpiece - 2 * h * i - dxZ;
                            tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx, tz));

                            //gcode.AddFrame(gcode.SetRelativeCoords());
                            tx += dxL + dxZ; tz += -(L + Z - W);
                            gcode.AddFrame(gcode.Move(tx, tz, F));

                            tx += R; tz += 0;
                            gcode.AddFrame(gcode.Move(tx, tz, F));
                            //gcode.AddFrame(gcode.SetAbsoluteCoords());
                            
                            tx = Dpiece - 2 * h * i;
                            tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx + 2 * X, tz) + "\n"
                                + ((ost > 0.00001) ? "" : "\n"));
                        }
                        if (ost > 0.00001)
                        {
                            tx = Dpiece - 2 * h * n - ost - dxZ;
                            tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx, tz));

                            //gcode.AddFrame(gcode.SetRelativeCoords());
                            tx += dxL + dxZ; tz += -(L + Z - W);
                            gcode.AddFrame(gcode.Move(tx, tz, F));

                            tx += R; tz += 0;
                            gcode.AddFrame(gcode.Move(tx, tz, F));
                            //gcode.AddFrame(gcode.SetAbsoluteCoords());

                            tx = Dpiece - 2 * h * n - ost;
                            tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx + 2 * X, tz) + "\n\n");
                        }
                        return true;
                    }
                case TransitionType.RadiusTurningClockwise:
                    {
                        float D = radiusTurningClockwise.D;
                        float L = radiusTurningClockwise.L;
                        float Dpiece = radiusTurningClockwise.Dpiece;
                        float Lpiece = radiusTurningClockwise.Lpiece;
                        float U = radiusTurningClockwise.U;
                        float W = radiusTurningClockwise.W;
                        float F = radiusTurningClockwise.F;
                        float h = radiusTurningClockwise.h;
                        float R = radiusTurningClockwise.R;
                        float S = radiusTurningClockwise.S;
                        float X = radiusTurningClockwise.X;
                        float Z = radiusTurningClockwise.Z;
                        float B = radiusTurningClockwise.B;
                        int ToolNumber = radiusTurningClockwise.ToolNumber;
                        int ToolDepartureNumber = radiusTurningClockwise.ToolDepartureNumber;
                        bool MachinePause = radiusTurningClockwise.MachinePause;
                        float d = radiusTurningClockwise.d;
                        float r = radiusTurningClockwise.r;

                        float tanalpha = (D - d) / (2 * L);
                        //float koef = (float)Math.Sqrt(tanalpha * tanalpha + 1);
                        //h *= koef; U *= koef;
                        float dxL = L * tanalpha;
                        float dxZ = 0;


                        //Dpiece = D + 2*U + 2*ost + 2*n*h
                        int n = (int)((Dpiece - d - 2 * U) / (2 * h));
                        float ost = (Dpiece - d - 2 * U) - (2 * n * h);


                        float tx = Dpiece;
                        float tz = Z - B;

                        if (MachinePause) gcode.AddFrame(gcode.StopWithContinuationIfNecessary());
                        gcode.AddFrame(gcode.SetTheTool(ToolNumber, ToolDepartureNumber));
                        gcode.AddFrame(gcode.SetTheRotationClockwise(S) + "\n");
                        for (int i = 1; i <= n; i++)
                        {
                            tx = Dpiece - 2 * h * i - dxZ;
                            tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx, tz));

                            //gcode.AddFrame(gcode.SetRelativeCoords());
                            tx += 0; tz += -Z;
                            gcode.AddFrame(gcode.Move(tx, tz, F));

                            tx += 2 * dxL; tz += -(L - W);
                            gcode.AddFrame(gcode.CircleMoveClockwise(tx, tz, r, F));

                            tx += R; tz += 0;
                            gcode.AddFrame(gcode.Move(tx, tz, F));
                            //gcode.AddFrame(gcode.SetAbsoluteCoords());

                            tx = Dpiece - 2 * h * i;
                            tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx + 2 * X, tz) + "\n"
                                + ((ost > 0.00001) ? "" : "\n"));
                        }
                        if (ost > 0.00001)
                        {
                            tx = Dpiece - 2 * h * n - ost - dxZ;
                            tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx, tz));

                            tx += 0; tz += -Z;
                            gcode.AddFrame(gcode.Move(tx, tz, F));

                            tx += 2 * dxL; tz += -(L - W);
                            gcode.AddFrame(gcode.CircleMoveClockwise(tx, tz, r, F));

                            tx += R; tz += 0;
                            gcode.AddFrame(gcode.Move(tx, tz, F));

                            tx = Dpiece - 2 * h * n - ost;
                            tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx + 2 * X, tz) + "\n\n");
                        }
                        /*
                        for (int i = 1; i <= n; i++)
                        {
                            tx = Dpiece - 2 * h * i;
                            gcode.AddFrame(gcode.FastMove(tx - dxZ, Z - B));
                            gcode.AddFrame(gcode.SetRelativeCoords());
                            gcode.AddFrame(gcode.Move(0, -Z, F));
                            gcode.AddFrame(gcode.CircleMoveClockwise(2 * dxL, -(L - W), r, F));
                            gcode.AddFrame(gcode.Move(R, 0, F));
                            gcode.AddFrame(gcode.SetAbsoluteCoords());
                            gcode.AddFrame(gcode.FastMove(tx + 2 * X, Z - B) + "\n"
                                + ((ost > 0.00001) ? "" : "\n"));
                        }
                        if (ost > 0.00001)
                        {
                            gcode.AddFrame(gcode.FastMove(Dpiece - 2 * h * n - ost - dxZ, Z - B));
                            gcode.AddFrame(gcode.SetRelativeCoords());
                            gcode.AddFrame(gcode.Move(0, -Z, F));
                            gcode.AddFrame(gcode.CircleMoveClockwise(2 * dxL, -(L - W), r, F));
                            gcode.AddFrame(gcode.Move(R, 0, F));
                            gcode.AddFrame(gcode.SetAbsoluteCoords());
                            gcode.AddFrame(gcode.FastMove(Dpiece - 2 * h * n - ost + 2 * X, Z - B) + "\n\n");
                        }*/
                        return true;
                    }
                case TransitionType.RadiusTurningAnticlockwise:
                    {
                        float D = radiusTurningAnticlockwise.D;
                        float L = radiusTurningAnticlockwise.L;
                        float Dpiece = radiusTurningAnticlockwise.Dpiece;
                        float Lpiece = radiusTurningAnticlockwise.Lpiece;
                        float U = radiusTurningAnticlockwise.U;
                        float W = radiusTurningAnticlockwise.W;
                        float F = radiusTurningAnticlockwise.F;
                        float h = radiusTurningAnticlockwise.h;
                        float R = radiusTurningAnticlockwise.R;
                        float S = radiusTurningAnticlockwise.S;
                        float X = radiusTurningAnticlockwise.X;
                        float Z = radiusTurningAnticlockwise.Z;
                        float B = radiusTurningAnticlockwise.B;
                        int ToolNumber = radiusTurningAnticlockwise.ToolNumber;
                        int ToolDepartureNumber = radiusTurningAnticlockwise.ToolDepartureNumber;
                        bool MachinePause = radiusTurningAnticlockwise.MachinePause;
                        float d = radiusTurningAnticlockwise.d;
                        float r = radiusTurningAnticlockwise.r;

                        float tanalpha = (D - d) / (2 * L);
                        //float koef = (float)Math.Sqrt(tanalpha * tanalpha + 1);
                        //h *= koef; U *= koef;
                        float dxL = L * tanalpha;
                        float dxZ = 0;


                        //Dpiece = D + 2*U + 2*ost + 2*n*h
                        int n = (int)((Dpiece - d - 2 * U) / (2 * h));
                        float ost = (Dpiece - d - 2 * U) - (2 * n * h);

                        float tx = Dpiece;
                        float tz = Z - B;

                        if (MachinePause) gcode.AddFrame(gcode.StopWithContinuationIfNecessary());
                        gcode.AddFrame(gcode.SetTheTool(ToolNumber, ToolDepartureNumber));
                        gcode.AddFrame(gcode.SetTheRotationClockwise(S) + "\n");
                        for (int i = 1; i <= n; i++)
                        {
                            tx = Dpiece - 2 * h * i - dxZ;
                            tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx, tz));

                            //gcode.AddFrame(gcode.SetRelativeCoords());
                            tx += 0; tz += -Z;
                            gcode.AddFrame(gcode.Move(tx, tz, F));

                            tx += 2 * dxL; tz += -(L - W);
                            gcode.AddFrame(gcode.CircleMoveAnticlockwise(tx, tz, r, F));

                            tx += R; tz += 0;
                            gcode.AddFrame(gcode.Move(tx, tz, F));
                            //gcode.AddFrame(gcode.SetAbsoluteCoords());

                            tx = Dpiece - 2 * h * i;
                            tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx + 2 * X, tz) + "\n"
                                + ((ost > 0.00001) ? "" : "\n"));
                        }
                        if (ost > 0.00001)
                        {
                            tx = Dpiece - 2 * h * n - ost - dxZ;
                            tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx, tz));

                            tx += 0; tz += -Z;
                            gcode.AddFrame(gcode.Move(tx, tz, F));

                            tx += 2 * dxL; tz += -(L - W);
                            gcode.AddFrame(gcode.CircleMoveAnticlockwise(tx, tz, r, F));

                            tx += R; tz += 0;
                            gcode.AddFrame(gcode.Move(tx, tz, F));

                            tx = Dpiece - 2 * h * n - ost;
                            tz = Z - B;
                            gcode.AddFrame(gcode.FastMove(tx + 2 * X, tz) + "\n\n");
                        }
                        /*
                        for (int i = 1; i <= n; i++)
                        {
                            tx = Dpiece - 2 * h * i;
                            gcode.AddFrame(gcode.FastMove(tx - dxZ, Z - B));
                            gcode.AddFrame(gcode.SetRelativeCoords());
                            gcode.AddFrame(gcode.Move(0, -Z, F));
                            gcode.AddFrame(gcode.CircleMoveAnticlockwise(2 * dxL, -(L - W), r, F));
                            gcode.AddFrame(gcode.Move(R, 0, F));
                            gcode.AddFrame(gcode.SetAbsoluteCoords());
                            gcode.AddFrame(gcode.FastMove(tx + 2 * X, Z - B) + "\n"
                                + ((ost > 0.00001) ? "" : "\n"));
                        }
                        if (ost > 0.00001)
                        {
                            gcode.AddFrame(gcode.FastMove(Dpiece - 2 * h * n - ost - dxZ, Z - B));
                            gcode.AddFrame(gcode.SetRelativeCoords());
                            gcode.AddFrame(gcode.Move(0, -Z, F));
                            gcode.AddFrame(gcode.CircleMoveAnticlockwise(2 * dxL, -(L - W), r, F));
                            gcode.AddFrame(gcode.Move(R, 0, F));
                            gcode.AddFrame(gcode.SetAbsoluteCoords());
                            gcode.AddFrame(gcode.FastMove(Dpiece - 2 * h * n - ost + 2 * X, Z - B) + "\n\n");
                        }*/
                        return true;
                    }
                default:
                    return false;
            }
        }

    }

    public class Operation
    {
        public List<Transition> transitions;
        public string description;
        public void Init(string name)
        {
            transitions = new List<Transition>();
            description = name;
        }
        public static Operation Load(string FileSpec)
        {
            XmlSerializer formatter = new XmlSerializer(typeof(Operation));

            using (FileStream aFile = new FileStream(FileSpec, FileMode.Open))
            {
                byte[] buffer = new byte[aFile.Length];
                aFile.Read(buffer, 0, (int)aFile.Length);

                using (MemoryStream stream = new MemoryStream(buffer))
                {
                    return (Operation)formatter.Deserialize(stream);
                }
                aFile.Close();
            }
        }

        public static void Save(Operation ToSerialize, string FileSpec)
        {
            Directory.CreateDirectory(FileSpec.Substring(0, FileSpec.LastIndexOf('\\')));
            FileStream outFile = File.Create(FileSpec);
            XmlSerializer formatter = new XmlSerializer(typeof(Operation));

            formatter.Serialize(outFile, ToSerialize);
            outFile.Close();
        }
    }
    
}
